package com.ncmmall.api.apis.mall;


import com.ncmmall.api.apis.service.Result;
import com.ncmmall.api.params.WebUserDTO;
import com.ncmmall.api.security.Securitys;
import com.ncmmall.api.utils.WXBizDataCrypt;
import com.ncmmall.application.business.member.MemberApplication;
import com.ncmmall.cache.redis.RedisService;
import com.feijin.commons.securitys.MD5HashUtils;
import com.ncmmall.domain.business.news.News;
import com.ncmmall.domain.business.news.QNews;
import com.ncmmall.domain.business.setting.SystemSetting;
import com.ncmmall.domain.security.user.QWebUser;
import com.ncmmall.domain.security.user.WebUser;
import com.ncmmall.querychannel.service.QueryChannelService;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author linxs
 * 用户注册、登录、退出接口
 */
@RestController
@RequestMapping(value = "/security")
@Component
public class UserApi {

    private Logger log = LoggerFactory.getLogger(UserApi.class);

    @Autowired
    private QueryChannelService queryChannelService;

    @Autowired
    private MemberApplication memberApplication;

    @Value("${store.domain}")
    private String storeDomain;

    @Value("${store.path}")
    private String storePath;

    @Value("${wx.appid}")
    private String appid;

    @Value("${wx.appSecret}")
    private String appSecret;

    @Autowired
    private RedisService redisService;

    /**
     * 登录
     *
     * @param params
     * @return
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    @ResponseBody
    public Result login(HttpServletRequest request, @RequestBody WebUser params) {
        Result result = new Result();
        try {

            WebUser user = queryChannelService.findOne("select u from WebUser u where u.username = :username and u.role.name = 'MERCHANT' ", ImmutableMap.of("username", params.getUsername()), WebUser.class);

            if (user != null) {

                if (!user.isAccountNonLocked()) {
                    return result.fail().setMsg("当前账号禁止登录");
                }

                String passwordAsMd5 = MD5HashUtils.asMD5(params.getPassword(), params.getUsername());

                if (user.getPassword().equals(passwordAsMd5)) {
                    user = memberApplication.login(user, Securitys.ipAddress(request));
                    log.info("[登录会员]" + user.getId() + "  " + user.getRealName() + "   " + user.getUsername() + "   " + user.getAccessToken() + "   " + user.getRefreshToken() + "    " + user.getMobile());
                    return result.ok().inject(ImmutableMap.of("token", user.getAccessToken(), "refreshToken", user.getRefreshToken(), "bindMobileStatus", !Strings.isNullOrEmpty(user.getMobile())));
                }

                return result.fail().setMsg("账号密码错误");
            }


            return result.fail().setMsg("账号不存在");

        } catch (Exception e) {
            log.error("[登录异常]", e);
            return result.fail().setMsg("登录异常");
        }

    }

    /**
     * token过期后，24小时内可以获取新的token
     *
     * @param request
     * @param params
     * @return
     */
    @RequestMapping(value = "/refreshToken", method = RequestMethod.POST)
    @ResponseBody
    public Result refreshToken(HttpServletRequest request, @RequestBody WebUser params) {
        Result result = new Result();
        try {

            WebUser user = queryChannelService.queryOneEntity("select u.* from security_web_user u where u.refreshToken=:token and u.loginTime > DATE_ADD(NOW(), INTERVAL -1440 MINUTE)", ImmutableMap.of("token", params.getRefreshToken()), WebUser.class);

            if (user != null) {
                memberApplication.login(user, Securitys.ipAddress(request));
                return result.ok().inject(ImmutableMap.of("token", user.getAccessToken(), "refreshToken", user.getRefreshToken()));
            }

            return result.fail().setMsg("登录信息已过期");

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return result.fail().setMsg("登录异常");
        }

    }

    /**
     * 微信小程序授权获取手机号快捷登录
     *
     * @param request
     * @param params
     * @return
     */
    @RequestMapping(value = "/wechatRegister", method = RequestMethod.POST)
    @ResponseBody
    public Result wechatRegister(HttpServletRequest request, @RequestBody WebUserDTO params) {
        Result result = new Result();
        try {

            WXBizDataCrypt pc = new WXBizDataCrypt(appid, params.getSessionKey());
            JSONObject wechatData = pc.decryptData(params.getEncryptedData(), params.getIv());

            String username = wechatData.getString("purePhoneNumber");

            WebUser user = queryChannelService.findOne("select u from WebUser u where u.username = :username and u.role.name = 'MERCHANT' ", ImmutableMap.of("username", username), WebUser.class);

            if (null != user) {
                user = memberApplication.login(user, Securitys.ipAddress(request));
                return result.ok().inject(ImmutableMap.of("token", user.getAccessToken(), "refreshToken", user.getRefreshToken()));
            }

            user = new WebUser();
            user.setUsername(username);
            user.setPassword(MD5HashUtils.asMD5("123456", username));
            user.setMobile(user.getUsername());
            user.setOpenId(params.getOpenid());

            memberApplication.register(user);

            user = memberApplication.login(user, Securitys.ipAddress(request));
            return result.ok().inject(ImmutableMap.of("token", user.getAccessToken(), "refreshToken", user.getRefreshToken()));

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return result.fail().setMsg("注册异常");
        }

    }


    /**
     * 注册
     *
     * @param request
     * @param params
     * @return
     */
    @RequestMapping(value = "/register", method = RequestMethod.POST)
    @ResponseBody
    public Result register(HttpServletRequest request, @RequestBody WebUserDTO params) {
        Result result = new Result();
        try {

            WebUser user = queryChannelService.findOne("select u from WebUser u where u.username = :username and u.role.name = 'MERCHANT' ", ImmutableMap.of("username", params.getUsername()), WebUser.class);

            if (null != user) {
                return result.fail().setMsg("账号已存在，请直接登录");
            }

            String code = redisService.get("msm-" + params.getUsername());
            if (!params.getMobileCode().equals(code)) {
                return result.fail().setMsg("短信验证码不正确");
            }

            user = new WebUser();
            user.setUsername(params.getUsername());
            user.setPassword(MD5HashUtils.asMD5(params.getPassword(), params.getUsername()));
            user.setMobile(user.getUsername());
            user.setOpenId(params.getOpenid());

            memberApplication.register(user);

            user = memberApplication.login(user, Securitys.ipAddress(request));
            return result.ok().inject(ImmutableMap.of("token", user.getAccessToken(), "refreshToken", user.getRefreshToken()));

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return result.fail().setMsg("注册异常");
        }

    }

    /**
     * 获取用户信息
     */
    @RequestMapping(value = "/userInfo", method = RequestMethod.GET)
    @ResponseBody
    public Result userInfo(HttpServletRequest request) {
        Result result = new Result();
        try {
            WebUser member = Securitys.cleanUser(Securitys.user(request));
            member.setMessageCount(member.getSystemMessageNumber() + member.getOrderMessageNumber() + member.getWithDrawMessageNumber());

            Map<String, Object> map = ImmutableMap.of("mid", member.getId());
            int nonPaymentOrders = queryChannelService.selectCount("select count(*) from mall_order where member_id = :mid and status = 1", map);
            int unfilledOrders = queryChannelService.selectCount("select count(*) from mall_order where member_id = :mid and status = 2", map);
            int nonReceiveOrders = queryChannelService.selectCount("select count(*) from mall_order where member_id = :mid and status in (3, 10)", map);
            int nonCommentOrders = queryChannelService.selectCount("select count(*) from mall_order where member_id = :mid and status = 4", map);
            int afterSaleOrders = queryChannelService.selectCount("select count(*) from mall_order where member_id = :mid and isAfterSale = 1", map);

            member.setNonPaymentOrders(nonPaymentOrders);
            member.setUnfilledOrders(unfilledOrders);
            member.setNonReceiveOrders(nonReceiveOrders);
            member.setNonCommentOrders(nonCommentOrders);
            member.setAfterSaleOrders(afterSaleOrders);

            List<News> newses = queryChannelService.findAll(QNews.news.status.eq(2).and(QNews.news.recommend.eq(2)).and(QNews.news.platformType.eq(1)), News.class);
            newses.forEach(news -> news.setContent(null));

            int count = queryChannelService.selectCount("select count(*) from mall_goods_collect where member_id = :mid", map);
            member.setCollectCount(count);
            member.setNewses(newses);

            return result.ok().inject(member);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return result.fail().setMsg(e.getMessage());
        }
    }


    /**
     * 更改昵称
     *
     * @param request
     * @param webUserDTO
     * @return
     */
    @RequestMapping(value = "/modifyNickname", method = RequestMethod.PUT)
    @ResponseBody
    public Result modifyNickname(HttpServletRequest request, @RequestBody WebUserDTO webUserDTO) {

        Result result = new Result();

        try {

            WebUser member = Securitys.user(request);

            memberApplication.modifyNickname(member, webUserDTO.getNickname());

            return result.ok();

        } catch (Exception e) {
            log.error("[修改昵称异常]", e);
            return result.fail().setMsg("修改失败");
        }

    }

    /**
     * 修改性别
     *
     * @param request
     * @param webUserDTO
     * @return
     */
    @RequestMapping(value = "/sex", method = RequestMethod.PUT)
    @ResponseBody
    public Result sex(HttpServletRequest request, @RequestBody WebUserDTO webUserDTO) {

        Result result = new Result();

        try {

            WebUser member = Securitys.user(request);

            memberApplication.modifySex(member, webUserDTO.getSex());

            return result.ok();

        } catch (Exception e) {
            log.error("[修改昵称异常]", e);
            return result.fail().setMsg("修改失败");
        }

    }


    /**
     * 更改个性签名
     *
     * @param request
     * @param webUserDTO
     * @return
     */
    @RequestMapping(value = "/modifySignature", method = RequestMethod.PUT)
    @ResponseBody
    public Result modifySignature(HttpServletRequest request, @RequestBody WebUserDTO params) {

        Result result = new Result();

        try {

            WebUser member = Securitys.user(request);
            memberApplication.modifySignature(member, params.getSignature());

            return result.ok();

        } catch (Exception e) {
            log.error("[修改个性签名异常]", e);
            return result.fail().setMsg("修改失败");
        }

    }


    /**
     * 更改头像
     *
     * @param request
     * @param webUserDTO
     * @return
     */
    @RequestMapping(value = "/modifyAvatar", method = RequestMethod.PUT)
    @ResponseBody
    public Result modifyAvatar(HttpServletRequest request, @RequestBody WebUserDTO params) {
        Result result = new Result();
        try {

            WebUser member = Securitys.user(request);
            memberApplication.modifyAvatar(member, params.getAvatar());

            return result.ok();

        } catch (Exception e) {
            log.error("[修改头像异常]", e);
            return result.fail().setMsg("修改失败");
        }
    }

    /**
     * 修改密码
     *
     * @param request
     * @param webUserDTO
     * @return
     */
    @RequestMapping(value = "/modifyPassword", method = RequestMethod.PUT)
    @ResponseBody
    public Result editPassword(HttpServletRequest request, @RequestBody WebUserDTO webUserDTO) {
        Result result = new Result();
        try {

            WebUser user = Securitys.user(request);

            if (StringUtils.isBlank(webUserDTO.getMobileCode()) || !webUserDTO.getMobileCode().equals(redisService.get("msm-" + user.getMobile()))) {
                return result.fail().setMsg("验证码不正确");
            }

            memberApplication.modifyPassword(user, webUserDTO.getNewPassword());
            return result.ok();

        } catch (Exception e) {
            log.error("[修改密码异常]", e);
            return result.fail().setMsg("修改失败");
        }

    }

    /**
     * 退出登录
     *
     * @param request
     * @return
     */
    @RequestMapping(value = "/logout", method = RequestMethod.POST)
    @ResponseBody
    public Result logout(HttpServletRequest request) {
        Result result = new Result();

        try {

            memberApplication.logout(Securitys.token(request));
            return result.ok();

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return result.fail().setMsg("退出失败");
        }
    }

    /**
     * 忘记密码
     *
     * @param webUserDTO
     * @return
     */
    @RequestMapping(value = "/forgetPassword", method = RequestMethod.PUT)
    @ResponseBody
    public Result forget(@RequestBody WebUserDTO webUserDTO) {

        Result result = new Result();

        try {

            WebUser webUser = queryChannelService.findOne(QWebUser.webUser.username.eq(webUserDTO.getUsername()), WebUser.class);

            if (webUser == null) {
                return result.fail().setMsg("用户不存在");
            }

            //短信验证码
            if (StringUtils.isBlank(webUserDTO.getMobileCode()) || !redisService.get("msm-" + webUserDTO.getUsername()).equals(webUserDTO.getMobileCode())) {
                return result.fail().setMsg("验证码错误");
            }

            memberApplication.modifyPassword(webUser, webUserDTO.getNewPassword());

            return result.ok();

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return result.fail().setMsg("获取数据异常");
        }
    }

    /**
     * 绑定手机号
     *
     * @param webUserDTO
     * @return
     */
    @RequestMapping(value = "/bindMobile", method = RequestMethod.PUT)
    @ResponseBody
    public Result bindMobile(HttpServletRequest request, @RequestBody WebUserDTO webUserDTO) {

        Result result = new Result();

        try {

            WebUser webUser = Securitys.user(request);

            if (webUser == null) {
                return result.fail().setMsg("用户不存在");
            }

            //短信验证码
            if (StringUtils.isBlank(webUserDTO.getMobileCode()) || !redisService.get("msm-" + webUserDTO.getMobile()).equals(webUserDTO.getMobileCode())) {
                return result.fail().setMsg("验证码错误");
            }

            memberApplication.bindMobile(webUser, webUserDTO.getMobile());

            return result.ok();

        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return result.fail().setMsg("获取数据异常");
        }
    }

    /**
     * 获取用户注册协议及商家入驻协议
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/protocol", method = RequestMethod.GET)
    @ResponseBody
    public Result protocol(HttpServletRequest request, HttpServletResponse response) {
        Result result = new Result();

        try {

            SystemSetting setting = queryChannelService.queryOneEntity("select * from mall_system_setting limit 1", Collections.emptyMap(), SystemSetting.class);

            return result.ok().inject(ImmutableMap.of("memberRegisterProtocol", setting.getRegisterProtocol(), "merchantEnterProtocol", setting.getMerchantEnterProtocol()));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            result.fail().setMsg(e.getMessage());
        }

        return result;
    }

}
